from asgiref.sync import sync_to_async
from cy_query.db import connections,DEFAULT_DB_ALIAS,models
from cy_query.apps import apps
from cy_query.db.utils import ProgrammingError

__all__ = ['MigrationManager','MigrateTable']


class MigrationManager(object):
    def __init__(self,database=DEFAULT_DB_ALIAS):
        self.database = database

    def all_create_tables(self):
        connection = connections[self.database]
        array = []
        with connection.schema_editor(collect_sql=True) as editor:
            for model in apps.get_models():
                if model._meta.abstract or not model._meta.managed:
                    continue
                try:
                    model.objects.first()
                except ProgrammingError:
                    sql,params = editor.table_sql(model)
                    array.append(sql % params)
        for i in array:
            with connection.cursor() as cursor:
                cursor.execute(i)
        return '\n'.join(array)

    async def aall_create_tables(self):
        return await sync_to_async(self.all_create_tables)()


class MigrateTable:
    def __init__(self, using=DEFAULT_DB_ALIAS):
        self.using = using
        self._sql = list()

    def create_table(self, model, collect_sql=True):
        with connections[self.using].schema_editor(collect_sql=collect_sql) as editor:
            editor.create_model(model)
            if collect_sql:
                self._sql = editor.collected_sql
                return self._sql

    def alter_field_table(self, model, old_field_name: str, new_field: models.Field, collect_sql=True):
        old_field = model._meta.get_field(old_field_name)
        with connections[self.using].schema_editor(collect_sql=collect_sql) as editor:
            editor.alter_field(
                model=model,
                old_field=old_field,
                new_field=new_field,
            )
            if collect_sql:
                self._sql = editor.collected_sql
                return self._sql

    def add_field(self, model, field: models.Field, collect_sql=True):
        with connections[self.using].schema_editor(collect_sql=collect_sql) as editor:
            editor.add_field(
                model=model,
                field=field
            )
            if collect_sql:
                self._sql = editor.collected_sql
                return self._sql

    def remove_field(self, model, field_name: str, collect_sql=True):
        field = model._meta.get_field(field_name)
        with connections[self.using].schema_editor(collect_sql=collect_sql) as editor:
            editor.alter_field(
                model=model,
                field=field
            )
            if collect_sql:
                self._sql = editor.collected_sql
                return self._sql

    def run_sql(self):
        if not self._sql:
            raise ValueError("未获取到sql语句")
        with connections[self.using].cursor() as cursor:
            for sql in self._sql:
                cursor.execute(sql)
        self._sql.clear()

# 示例
# migrate = MigrateTable()
# 打印生成的SQL
# migrate.create_table(OperationLogModel,collect_sql=False)